3ddb79bccYVzXZJyVaxuv5T42Z1Fsw xen/arch/x86/trampoline.S
3ddb79bcOftONV9h4QCxXOfiT0h91w xen/arch/x86/traps.c
41c0c411tD3C7TpfDMiFTf7BaNd_Dg xen/arch/x86/vmx.c
+420951dcf1rSGnCH0AEYN2KjWGLG6A xen/arch/x86/vmx_intercept.c
41c0c411ODt8uEmV-yUxpQLpqimE5Q xen/arch/x86/vmx_io.c
41f97ef5139vN42cOYHfX_Ac8WOOjA xen/arch/x86/vmx_platform.c
41c0c4128URE0dxcO15JME_MuKBPfg xen/arch/x86/vmx_vmcs.c
40cf1596saFaHD5DC5zvrSn7CDCWGQ xen/include/asm-x86/uaccess.h
41c0c412k6GHYF3cJtDdw37ee3TVaw xen/include/asm-x86/vmx.h
41c0c412hck3QX-6_MaXaISGkngQuA xen/include/asm-x86/vmx_cpu.h
+420951dcGoqsqnmjjAtEtm6-3dM9KA xen/include/asm-x86/vmx_intercept.h
41c0c41243jC1mcArZx_t3YkBL4lTA xen/include/asm-x86/vmx_platform.h
+420951dcqyUCe_gXA_XJPu1ix_poKg xen/include/asm-x86/vmx_virpit.h
41c0c412lQ0NVVN9PsOSznQ-qhOiPA xen/include/asm-x86/vmx_vmcs.h
418fbcfe_WliJPToeVM-9VStvym-hw xen/include/asm-x86/x86_32/asm_defns.h
3ddb79c2ADvRmdexd9y3AYK9_NTx-Q xen/include/asm-x86/x86_32/current.h
}
}
}
- req->state = STATE_IORESP_READY;
+
+ /* No state change if state = STATE_IORESP_HOOK */
+ if (req->state == STATE_IOREQ_INPROCESS)
+ req->state = STATE_IORESP_READY;
+
send_event = 1;
}
BX_DBG_IAC_REPORT(vector, irq);
return(vector);
}
+
+ Bit8u
+bx_pic_c::irq_to_vec(Bit8u irq)
+{
+ Bit8u vector = 0;
+
+ if (irq >= 8 && irq <= 15)
+ vector = irq + BX_PIC_THIS s.slave_pic.interrupt_offset;
+ else if (irq != 2 && irq <= 7)
+ vector = irq + BX_PIC_THIS s.master_pic.interrupt_offset;
+ else
+ BX_ERROR(("invalid irq!\n"));
+
+ return vector;
+}
void
bx_pic_c::show_pic_state(void)
class bx_pic_c : public bx_pic_stub_c {
-
public:
bx_pic_c(void);
~bx_pic_c(void);
virtual void raise_irq(unsigned irq_no);
virtual Bit8u IAC(void);
virtual void show_pic_state(void);
+ Bit8u irq_to_vec(Bit8u);
private:
struct {
return 0;
}
+#ifdef BX_VMX_PIT
+//extra operations when use vmx pit device model
+ void pit_82C54::write_initcount_vmx(Bit8u cnum) {
+ if(cnum>MAX_COUNTER) {
+ BX_ERROR(("Counter number incorrect\n"));
+ }
+
+ ioreq_t *req = &((vcpu_iodata_t *) shared_page)->vp_ioreq;
+ extern bx_pic_c *thePic;
+ counter_type & thisctr = counter[cnum];
+ if(req->pdata_valid) {
+ BX_ERROR(("VMX_PIT:err!pit is port io!\n"));
+ }
+
+ if (thisctr.mode == 2) {//periodic mode, need HV to help send interrupt
+ req->state = STATE_IORESP_HOOK;
+
+// req->u.data = thisctr.inlatch * 1000 / PIT_FREQ;//init count:16 bit
+ req->u.data = thisctr.inlatch; //init count:16 bit
+ //get the pit irq(0)'s vector from pic DM
+ req->u.data |= ((thePic->irq_to_vec(0)) << 16 ); //timer vec:8 bit
+ req->u.data |= (cnum << 24); //PIT channel(0~2):2 bit
+ req->u.data |= ((thisctr.rw_mode) << 26); //rw mode:2 bit
+
+ BX_INFO(("VMX_PIT:whole pit hook packet = 0x%llx \n", (req->u.data ) ));
+ BX_INFO(("VMX_PIT:init counter = %d ms\n", (req->u.data & 0xFFFF) ));
+ }
+
+ }
+#endif
+
void pit_82C54::write(Bit8u address, Bit8u data) {
if(address>MAX_ADDRESS) {
BX_ERROR(("Counter address incorrect in data write."));
thisctr.inlatch=(thisctr.inlatch & (0xFF<<8)) | data;
thisctr.null_count=1;
thisctr.count_written=1;
+#ifdef BX_VMX_PIT
+ write_initcount_vmx(address);
+#endif
break;
case MSByte_multiple:
thisctr.write_state=LSByte_multiple;
thisctr.inlatch=(thisctr.inlatch & 0xFF) | (data<<8);
thisctr.null_count=1;
thisctr.count_written=1;
+#ifdef BX_VMX_PIT
+ write_initcount_vmx(address);
+#endif
break;
default:
BX_ERROR(("write counter in invalid write state."));
#include "bochs.h"
+#ifdef BX_USE_VMX
+#define BX_VMX_PIT 1
+#define PIT_FREQ 1193181
+#endif
+
class pit_82C54 : public logfunctions {
void print_counter(counter_type & thisctr);
+#ifdef BX_USE_VMX
+ void write_initcount_vmx(Bit8u cnum);
+#endif
+
public:
void init (void);
void reset (unsigned type);
(unsigned) address, (unsigned) value));
}
+#ifndef BX_VMX_PIT
if ((BX_PIT_THIS s.timer.read_OUT(0))==1) {
DEV_pic_raise_irq(0);
} else {
DEV_pic_lower_irq(0);
}
+#endif
if(time_passed ||
(BX_PIT_THIS s.last_next_event_time
BX_PIT_THIS s.timer.clock_all(timedelta);
if ( (prev_timer0_out==0) ) {
if ((BX_PIT_THIS s.timer.read_OUT(0))==1) {
+#ifndef BX_VMX_PIT
DEV_pic_raise_irq(0);
+#endif
prev_timer0_out=1;
}
} else {
if ((BX_PIT_THIS s.timer.read_OUT(0))==0) {
+#ifndef BX_VMX_PIT
DEV_pic_lower_irq(0);
+#endif
prev_timer0_out=0;
}
}
#ifdef CONFIG_VMX
static void vmx_domain_relinquish_memory(struct exec_domain *ed)
{
+ struct vmx_virpit_t *vpit = &(ed->arch.arch_vmx.vmx_platform.vmx_pit);
/*
* Free VMCS
*/
ed->arch.arch_vmx.vmcs = 0;
monitor_rm_pagetable(ed);
+ rem_ac_timer(&(vpit->pit_timer));
}
#endif
#include <asm/spinlock.h>
#include <asm/vmx.h>
#include <asm/vmx_vmcs.h>
+#include <asm/vmx_intercept.h>
#include <public/io/ioreq.h>
#ifdef CONFIG_VMX
}
p = &vio->vp_ioreq;
p->dir = test_bit(3, &exit_qualification);
- set_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags);
p->pdata_valid = 0;
p->count = 1;
p->addr = addr;
p->port_mm = 0;
+
+ /* Check if the packet needs to be intercepted */
+ if (vmx_io_intercept(p)) {
+ /* no blocking & no evtchn notification */
+ return;
+ }
+
+ set_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags);
p->state = STATE_IOREQ_READY;
evtchn_send(IOPACKET_PORT);
do_block();
--- /dev/null
+/*
+ * vmx_intercept.c: Handle performance critical I/O packets in hypervisor space
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <xen/config.h>
+#include <xen/types.h>
+#include <asm/vmx.h>
+#include <asm/vmx_platform.h>
+#include <asm/vmx_virpit.h>
+#include <asm/vmx_intercept.h>
+#include <public/io/ioreq.h>
+
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <asm/current.h>
+
+/* for intercepting io request after vm_exit, return value: 0--not handle; 1--handled */
+int vmx_io_intercept(ioreq_t *p)
+{
+ struct exec_domain *d = current;
+ struct vmx_handler_t *handler = &(d->arch.arch_vmx.vmx_platform.vmx_handler);
+ int i;
+ unsigned addr, offset;
+ for (i = 0; i < handler->num_slot; i++) {
+ addr = handler->hdl_list[i].addr;
+ offset = handler->hdl_list[i].offset;
+ if (p->addr >= addr &&
+ p->addr < addr + offset)
+ return handler->hdl_list[i].action(p);
+ }
+ return 0;
+}
+
+int register_io_handler(unsigned long addr, unsigned long offset, intercept_action_t action)
+{
+ struct exec_domain *d = current;
+ struct vmx_handler_t *handler = &(d->arch.arch_vmx.vmx_platform.vmx_handler);
+ int num = handler->num_slot;
+
+ if (num >= MAX_IO_HANDLER) {
+ printk("no extra space, register io interceptor failed!\n");
+ domain_crash();
+ }
+
+ handler->hdl_list[num].addr = addr;
+ handler->hdl_list[num].offset = offset;
+ handler->hdl_list[num].action = action;
+ handler->num_slot++;
+ return 1;
+
+}
+
+static void pit_cal_count(struct vmx_virpit_t *vpit)
+{
+ unsigned int usec_delta = (unsigned int)((NOW() - vpit->inject_point) / 1000);
+ if (usec_delta > vpit->period * 1000)
+ VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT:long time has passed from last injection!\n");
+ vpit->count = vpit->init_val - ((usec_delta * PIT_FREQ / 1000000) % vpit->init_val );
+}
+
+static void pit_latch_io(struct vmx_virpit_t *vpit)
+{
+ pit_cal_count(vpit);
+
+ switch(vpit->read_state) {
+ case MSByte:
+ vpit->count_MSB_latched=1;
+ break;
+ case LSByte:
+ vpit->count_LSB_latched=1;
+ break;
+ case LSByte_multiple:
+ vpit->count_LSB_latched=1;
+ vpit->count_MSB_latched=1;
+ break;
+ case MSByte_multiple:
+ VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT:latch PIT counter before MSB_multiple!");
+ vpit->read_state=LSByte_multiple;
+ vpit->count_LSB_latched=1;
+ vpit->count_MSB_latched=1;
+ break;
+ default:
+ BUG();
+ }
+}
+
+static int pit_read_io(struct vmx_virpit_t *vpit)
+{
+ if(vpit->count_LSB_latched) {
+ /* Read Least Significant Byte */
+ if(vpit->read_state==LSByte_multiple) {
+ vpit->read_state=MSByte_multiple;
+ }
+ vpit->count_LSB_latched=0;
+ return (vpit->count & 0xFF);
+ } else if(vpit->count_MSB_latched) {
+ /* Read Most Significant Byte */
+ if(vpit->read_state==MSByte_multiple) {
+ vpit->read_state=LSByte_multiple;
+ }
+ vpit->count_MSB_latched=0;
+ return ((vpit->count>>8) & 0xFF);
+ } else {
+ /* Unlatched Count Read */
+ VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT: unlatched read");
+ pit_cal_count(vpit);
+ if(!(vpit->read_state & 0x1)) {
+ /* Read Least Significant Byte */
+ if(vpit->read_state==LSByte_multiple) {
+ vpit->read_state=MSByte_multiple;
+ }
+ return (vpit->count & 0xFF);
+ } else {
+ /* Read Most Significant Byte */
+ if(vpit->read_state==MSByte_multiple) {
+ vpit->read_state=LSByte_multiple;
+ }
+ return ((vpit->count>>8) & 0xFF);
+ }
+ }
+}
+
+/* vmx_io_assist light-weight version, specific to PIT DM */
+static void resume_pit_io(ioreq_t *p)
+{
+ execution_context_t *ec = get_execution_context();
+ unsigned long old_eax = ec->eax;
+ p->state = STATE_INVALID;
+
+ switch(p->size) {
+ case 1:
+ ec->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff);
+ break;
+ case 2:
+ ec->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff);
+ break;
+ case 4:
+ ec->eax = (p->u.data & 0xffffffff);
+ break;
+ default:
+ BUG();
+ }
+}
+
+/* the intercept action for PIT DM retval:0--not handled; 1--handled */
+int intercept_pit_io(ioreq_t *p)
+{
+ struct exec_domain *d = current;
+ struct vmx_virpit_t *vpit = &(d->arch.arch_vmx.vmx_platform.vmx_pit);
+
+ if (p->size != 1 ||
+ p->pdata_valid ||
+ p->port_mm)
+ return 0;
+
+ if (p->addr == 0x43 &&
+ p->dir == 0 && /* write */
+ ((p->u.data >> 4) & 0x3) == 0 && /* latch command */
+ ((p->u.data >> 6) & 0x3) == (vpit->channel)) {/* right channel */
+ pit_latch_io(vpit);
+ return 1;
+ }
+
+ if (p->addr == (0x40 + vpit->channel) &&
+ p->dir == 1) { /* read */
+ p->u.data = pit_read_io(vpit);
+ resume_pit_io(p);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* hooks function for the PIT initialization response iopacket */
+static void pit_timer_fn(unsigned long data)
+{
+ struct vmx_virpit_t *vpit = (struct vmx_virpit_t*)data;
+
+ /* rearm itself */
+ vpit->pit_timer.expires = NOW() + MILLISECS(vpit->period);
+
+ /*set the pending intr bit in shared page, send evtchn notification to myself*/
+ if (test_and_set_bit(vpit->vector, vpit->intr_bitmap))
+ vpit->pending_intr_nr++; /* if originaly set, then count the pending intr */
+
+ add_ac_timer(&(vpit->pit_timer));
+}
+
+
+/* Only some PIT operations such as load init counter need a hypervisor hook.
+ * leave many other operations in user space DM
+ */
+void vmx_hooks_assist(struct exec_domain *d)
+{
+ vcpu_iodata_t *vio = (vcpu_iodata_t *) d->arch.arch_vmx.vmx_platform.shared_page_va;
+ ioreq_t *p = &vio->vp_ioreq;
+ unsigned long *intr = &(vio->vp_intr[0]);
+ struct vmx_virpit_t *vpit = &(d->arch.arch_vmx.vmx_platform.vmx_pit);
+ int rw_mode;
+
+ if (p->state == STATE_IORESP_HOOK) { /*load init count*/
+ vpit->init_val = (p->u.data & 0xFFFF) ; /* frequency(ms) of pit */
+ vpit->period = (vpit->init_val) * 1000 / PIT_FREQ; /* frequency(ms) of pit */
+ vpit->vector = ((p->u.data >> 16) & 0xFF);
+ vpit->channel = ((p->u.data >> 24) & 0x3);
+
+ vpit->count_LSB_latched = 0;
+ vpit->count_MSB_latched = 0;
+
+ rw_mode = ((p->u.data >> 26) & 0x3);
+ switch(rw_mode) {
+ case 0x1:
+ vpit->read_state=LSByte;
+ break;
+ case 0x2:
+ vpit->read_state=MSByte;
+ break;
+ case 0x3:
+ vpit->read_state=LSByte_multiple;
+ break;
+ default:
+ printk("VMX_PIT:wrong PIT rw_mode!\n");
+ break;
+ }
+
+ vpit->intr_bitmap = intr;
+
+ /* set up the actimer */
+ init_ac_timer(&(vpit->pit_timer));
+ vpit->pit_timer.cpu = 0; /*FIXME: change for SMP */
+ vpit->pit_timer.data = (unsigned long)vpit;
+ vpit->pit_timer.function = pit_timer_fn;
+ pit_timer_fn((unsigned long)vpit); /* timer seed */
+
+ /*restore the state*/
+ p->state = STATE_IORESP_READY;
+
+ /* register handler to intercept the PIT io when vm_exit */
+ register_io_handler(0x40, 4, intercept_pit_io);
+ }
+
+}
#include <xen/event.h>
#include <public/io/ioreq.h>
#include <asm/vmx_platform.h>
+#include <asm/vmx_virpit.h>
#ifdef CONFIG_VMX
domain_crash();
}
p = &vio->vp_ioreq;
+
+ if (p->state == STATE_IORESP_HOOK){
+ vmx_hooks_assist(ed);
+ }
+
/* clear IO wait VMX flag */
if (test_bit(ARCH_VMX_IO_WAIT, &ed->arch.arch_vmx.flags)) {
if (p->state != STATE_IORESP_READY) {
{
int highest_vector = find_highest_pending_irq(d);
unsigned long intr_fields, eflags;
+ struct vmx_virpit_t *vpit = &(d->arch.arch_vmx.vmx_platform.vmx_pit);
if (highest_vector == -1)
return;
return;
}
- clear_highest_bit(d, highest_vector);
+ if (vpit->pending_intr_nr && highest_vector == vpit->vector)
+ vpit->pending_intr_nr--;
+ else
+ clear_highest_bit(d, highest_vector);
+
intr_fields = (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR | highest_vector);
__vmwrite(VM_ENTRY_INTR_INFO_FIELD, intr_fields);
__vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
+ if (highest_vector == vpit->vector)
+ vpit->inject_point = NOW();
+
return;
}
--- /dev/null
+
+#ifndef _VMX_INTERCEPT_H
+#define _VMX_INTERCEPT_H
+
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/time.h>
+#include <xen/errno.h>
+#include <public/io/ioreq.h>
+
+
+#define MAX_IO_HANDLER 6
+
+typedef int (*intercept_action_t)(ioreq_t*);
+
+struct vmx_handler_t {
+ int num_slot;
+ struct {
+ unsigned long addr;
+ unsigned long offset;
+ intercept_action_t action;
+ } hdl_list[MAX_IO_HANDLER];
+};
+
+/* global io interception point in HV */
+extern int vmx_io_intercept(ioreq_t*);
+extern int register_io_handler(unsigned long, unsigned long, intercept_action_t);
+
+
+#endif /* _VMX_INTERCEPT_H */
#include <public/xen.h>
#include <asm/e820.h>
+#include <asm/vmx_virpit.h>
+#include <asm/vmx_intercept.h>
#define MAX_OPERAND_NUM 3
#define I_NAME_LEN 16
struct virutal_platform_def {
unsigned long *real_mode_data; /* E820, etc. */
unsigned long shared_page_va;
+ struct vmx_virpit_t vmx_pit;
+ struct vmx_handler_t vmx_handler;
struct mi_per_cpu_info mpci; /* MMIO */
};
--- /dev/null
+
+#ifndef _VMX_VIRPIT_H
+#define _VMX_VIRPIT_H
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/time.h>
+#include <xen/errno.h>
+#include <xen/ac_timer.h>
+#include <asm/vmx_vmcs.h>
+
+#define PIT_FREQ 1193181
+
+#define LSByte 0
+#define MSByte 1
+#define LSByte_multiple 2
+#define MSByte_multiple 3
+
+struct vmx_virpit_t {
+ /* for simulation of counter 0 in mode 2*/
+ int vector; /* the pit irq vector */
+ unsigned int period; /* the frequency. e.g. 10ms*/
+ unsigned int channel; /* the pit channel, counter 0~2 */
+ unsigned long *intr_bitmap;
+ unsigned int pending_intr_nr; /* the couner for pending timer interrupts */
+ unsigned long long inject_point; /* the time inject virt intr */
+ struct ac_timer pit_timer; /* periodic timer for mode 2*/
+
+ /* virtual PIT state for handle related I/O */
+ int read_state;
+ int count_LSB_latched;
+ int count_MSB_latched;
+
+ unsigned int count; /* the 16 bit channel count */
+ unsigned int init_val; /* the init value for the counter */
+
+} ;
+
+/* to hook the ioreq packet to get the PIT initializaiton info */
+extern void vmx_hooks_assist(struct exec_domain *d);
+
+#endif /* _VMX_VIRPIT_H_ */
+
+#ifndef _VMX_VIRPIT_H
+#define _VMX_VIRPIT_H
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/time.h>
+#include <xen/errno.h>
+#include <xen/ac_timer.h>
+#include <asm/vmx_vmcs.h>
+
+#define PIT_FREQ 1193181
+
+#define LSByte 0
+#define MSByte 1
+#define LSByte_multiple 2
+#define MSByte_multiple 3
+
+struct vmx_virpit_t {
+ /* for simulation of counter 0 in mode 2*/
+ int vector; /* the pit irq vector */
+ unsigned int period; /* the frequency. e.g. 10ms*/
+ unsigned int channel; /* the pit channel, counter 0~2 */
+ unsigned long *intr_bitmap;
+ unsigned int pending_intr_nr; /* the couner for pending timer interrupts */
+ unsigned long long inject_point; /* the time inject virt intr */
+ struct ac_timer pit_timer; /* periodic timer for mode 2*/
+
+ /* virtual PIT state for handle related I/O */
+ int read_state;
+ int count_LSB_latched;
+ int count_MSB_latched;
+
+ unsigned int count; /* the 16 bit channel count */
+ unsigned int init_val; /* the init value for the counter */
+
+} ;
+
+#endif /* _VMX_VIRPIT_H_ */
#define STATE_IOREQ_READY 1
#define STATE_IOREQ_INPROCESS 2
#define STATE_IORESP_READY 3
+#define STATE_IORESP_HOOK 4
#define IOPACKET_PORT 2